﻿using CPPEI.Coolzon.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace CPPEI.UpdatePackageTool
{
    public class XConfigUtil
    {
        private static List<Product> ListProduct;
        public static List<Product> Init(string configFile)
        {
            if (System.IO.File.Exists(configFile))
            {
                XmlDocument xmlDocument = new XmlDocument();
                try
                {
                    xmlDocument.Load(configFile);

                }
                catch (Exception ex)
                {
                    throw ex;
                }

                string rootName = "Products";

                XmlNode rootNode = null;
                XConfigUtil.ListProduct = new List<Product>();
                try
                {
                    ////根据xClassConfig的Name获取根节点
                    rootNode = xmlDocument.SelectSingleNode("./" + rootName);

                    if (rootNode == null || rootNode.ChildNodes == null)
                    {
                        return null;
                    }

                    foreach (XmlNode childNode in rootNode.ChildNodes)
                    {
                        XmlElement xe = (XmlElement)childNode;
                        Product product = new Product();
                        product.AppType = xe.GetAttribute("Type").ToString();
                        product.EName = xe.GetAttribute("Name").ToString();
                        // 得到Product节点的所有子节点
                        XmlNodeList childNodeList = xe.ChildNodes;
                        product.AppNumber = Convert.ToInt32(childNodeList.Item(0).InnerText);
                        product.CName = childNodeList.Item(1).InnerText;
                        product.CurrentVersionsPath = childNodeList.Item(2).InnerText;
                        product.PastVersionsPath = childNodeList.Item(3).InnerText;
                        product.CurrentVersion = childNodeList.Item(4).InnerText;
                        product.PastVersion = childNodeList.Item(5).InnerText;
                        ListProduct.Add(product);
                    }

                }
                catch (Exception ex)
                {
                    throw ex;
                }

            }
            return ListProduct;
        }


        public static void xiugai(Product product, string configFile)
        {

            if (System.IO.File.Exists(configFile))
            {
                XmlDocument xmlDocument = new XmlDocument();
                try
                {
                    xmlDocument.Load(configFile);

                }
                catch (Exception ex)
                {
                    throw ex;
                }

                XmlElement xe = xmlDocument.DocumentElement; // DocumentElement 获取xml文档对象的根XmlElement.
                string strPath = string.Format("/Products/Product[@Type=\"{0}\"]", product.AppType);
                XmlElement selectXe = (XmlElement)xe.SelectSingleNode(strPath);  //selectSingleNode 根据XPath表达式,获得符合条件的第一个节点.
                //selectXe.SetAttribute("Type", dgvBookInfo.CurrentRow.Cells[0].Value.ToString());//也可以通过SetAttribute来增加一个属性
                selectXe.GetElementsByTagName("Name").Item(0).InnerText = product.CName;
                selectXe.GetElementsByTagName("CurrentVersionPath").Item(0).InnerText = product.CurrentVersionsPath;
                selectXe.GetElementsByTagName("PastVersionPath").Item(0).InnerText = product.PastVersionsPath;
                selectXe.GetElementsByTagName("CurrentVersion").Item(0).InnerText = product.CurrentVersion;
                selectXe.GetElementsByTagName("PastVersion").Item(0).InnerText = product.PastVersion;
                xmlDocument.Save(configFile);
            }


        }


        /// <summary>
        /// 解析配置文件，初始化目标对象的各属性
        /// </summary>
        /// <param name="configFile"></param>
        /// <exception cref="ConfigException"></exception>
        public static void Init(object obj, string configFile)
        {
            if (System.IO.File.Exists(configFile))
            {
                XmlDocument xmlDocument = new XmlDocument();
                try
                {
                    xmlDocument.Load(configFile);

                }
                catch (Exception ex)
                {
                    throw ex;
                }

                string rootName = "Environment";
                //获取xml根节点名称，默认为Environment
                XConfigRootAttribute xClassConfig = (XConfigRootAttribute)obj.GetType().GetCustomAttribute(typeof(XConfigRootAttribute), true);
                if (xClassConfig != null && !string.IsNullOrEmpty(xClassConfig.Name))
                {
                    rootName = xClassConfig.Name;
                }

                XmlNode rootNode = null;
                try
                {
                    //根据xClassConfig的Name获取根节点
                    rootNode = xmlDocument.SelectSingleNode("./" + rootName);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                //为属性赋值
                PropertyInjection(obj, rootNode);
            }
        }

        /// <summary>
        /// 根据xml节点配置，赋值到对应的属性，并返回该对象
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="rootNode"></param>
        /// <returns></returns>
        private static object PropertyInjection(object obj, XmlNode rootNode)
        {
            //如果根节点为空，则为整个对象赋默认值
            if (rootNode == null)
            {
                ObjectInjectDefaultValue(obj);
            }
            else
            {
                //获取对象全部public属性
                PropertyInfo[] propertyInfoList = obj.GetType().GetProperties();
                foreach (PropertyInfo propertyInfo in propertyInfoList)
                {
                    XConfigAttribute xConfig = (XConfigAttribute)propertyInfo.GetCustomAttribute(typeof(XConfigAttribute), true);
                    if (xConfig != null)
                    {
                        XmlNode xmlNode = null;
                        try
                        {
                            //根据xConfig的名称获取xml中对应节点
                            xmlNode = rootNode.SelectSingleNode("./" + xConfig.Name);
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                        if (xmlNode != null)
                        {
                            try
                            {
                                //属性是枚举类型时
                                if (propertyInfo.PropertyType.IsEnum)
                                {
                                    propertyInfo.SetValue(obj, Enum.Parse(propertyInfo.PropertyType, xmlNode.Attributes["Value"].Value));
                                }
                                //属性是类并且不是string类型时
                                else if (propertyInfo.PropertyType.IsClass && propertyInfo.PropertyType != typeof(string))
                                {
                                    propertyInfo.SetValue(obj, PropertyInjection(propertyInfo.PropertyType.Assembly.CreateInstance(propertyInfo.PropertyType.FullName), xmlNode));
                                }
                                //其他值类型
                                else
                                {
                                    propertyInfo.SetValue(obj, Convert.ChangeType(xmlNode.Attributes["Value"].Value, propertyInfo.PropertyType));
                                }
                            }
                            catch (Exception ex)
                            {
                                throw ex;
                            }
                        }
                        //如果对应节点不存在则赋默认值
                        else
                        {
                            PropertyInjdectDefaultValue(obj, propertyInfo);
                        }
                    }
                }
            }
            return obj;
        }

        /// <summary>
        /// 为对象赋默认值
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static object ObjectInjectDefaultValue(object obj)
        {
            PropertyInfo[] propertyInfoList = obj.GetType().GetProperties();
            foreach (PropertyInfo propertyInfo in propertyInfoList)
            {
                PropertyInjdectDefaultValue(obj, propertyInfo);
            }
            return obj;
        }

        /// <summary>
        /// 为属性赋默认值
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="propertyInfo"></param>
        private static object PropertyInjdectDefaultValue(object obj, PropertyInfo propertyInfo)
        {
            XConfigAttribute xConfig = (XConfigAttribute)propertyInfo.GetCustomAttribute(typeof(XConfigAttribute), true);
            if (xConfig != null && xConfig.DefaultValue != null)
            {
                try
                {
                    //属性是枚举类型时
                    if (propertyInfo.PropertyType.IsEnum)
                    {
                        propertyInfo.SetValue(obj, Enum.Parse(propertyInfo.PropertyType, xConfig.DefaultValue.ToString()));
                    }
                    //属性是类并且不是string类型时
                    else if (propertyInfo.PropertyType.IsClass && propertyInfo.PropertyType != typeof(string))
                    {
                        propertyInfo.SetValue(obj, null);
                    }
                    //其他值类型
                    else
                    {
                        propertyInfo.SetValue(obj, Convert.ChangeType(xConfig.DefaultValue, propertyInfo.PropertyType));
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return obj;
        }
    }

    /// <summary>
    /// 自定义解析配置异常类
    /// </summary>
    public class ConfigException : Exception
    {
        /// <summary>
        /// 捕获到的所有异常
        /// </summary>
        public List<Exception> ExceptionList { get; set; }

        /// <summary>
        /// 重载Message，返回捕获到的所有Exception的Message,用‘;’分隔
        /// </summary>
        public override string Message
        {
            get
            {
                string retMessage = "";
                if (ExceptionList != null && ExceptionList.Count > 0)
                {
                    foreach (Exception ex in ExceptionList)
                    {
                        retMessage += ex.Message + ";";
                    }
                }
                return retMessage;
            }
        }
    }
}
